package com.aliyun.messagemgt.service;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.messagemgt.common.constant.CommonConstant;
import com.aliyun.messagemgt.common.enums.PushResultEnum;
import com.aliyun.messagemgt.common.enums.RangeTypeEnum;
import com.aliyun.messagemgt.common.dto.send.*;
import com.aliyun.messagemgt.common.enums.ChannelTypeEnum;
import com.aliyun.messagemgt.pojo.dto.DingTalkResponse;
import com.aliyun.messagemgt.pojo.dto.SysUserInfoDTO;
import com.aliyun.messagemgt.sendplugin.SendStrategy;
import com.aliyun.messagemgt.sendplugin.SendStrategyFactory;
import com.aliyun.messagemgt.util.DingTalkUtils;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.request.OapiMessageCorpconversationGetsendresultRequest;
import com.dingtalk.api.request.OapiUserGetByMobileRequest;
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.dingtalk.api.response.OapiMessageCorpconversationGetsendresultResponse;
import com.dingtalk.api.response.OapiUserGetByMobileResponse;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ClassName: DingdingSendStrategy
 * @Description:
 * @Author: wugongzi
 * @Date: 2021/8/30 11:15
 * @Version: 1.0
 */
@Service
@Slf4j
public class DingTalkSendStrategy implements SendStrategy, InitializingBean {

    @Value("${dingding.dingTalk.userIdByPhoneUrl}")
    private String userIdByPhoneUrl;
    @Value("${dingding.dingTalk.sendresultUrl}")
    private String sendresultUrl;
    @Value("${dingding.dingTalk.asyncsendV2Url}")
    private String asyncsendV2Url;

    @Override
    public void afterPropertiesSet() {
        SendStrategyFactory.register(ChannelTypeEnum.DING_TALK.getType(), this);
    }
    /**
     * 发送消息钉钉工作通知
     * @param pushChannelInfo
     * @param msgRecordVO
     */
    @Override
    public void sendMessage(PushChannelInfo pushChannelInfo, MsgRecordVO msgRecordVO) {
        List<MsgMiddleResult> results = msgRecordVO.getResults();
        List<Receiver> users = msgRecordVO.getReceivers();
        String corpId = pushChannelInfo.getCorpId();
        String corpSecret = pushChannelInfo.getCorpSecret();
        String token = DingTalkUtils.getAccessToken(corpId, corpSecret);
        if (null == token) {
            log.error("{} 无法获取到对应的token", pushChannelInfo);
            MsgMiddleResult msgMiddleResult = generateMsgMiddleResult(users, PushResultEnum.PUSH_TOKEN_INVALID);
            results.add(msgMiddleResult);
            return;
        }
        Long agentId = pushChannelInfo.getAgentId();
        try {
            sendDingTalkMsg(token, msgRecordVO, agentId);
        } catch (Exception e) {
            log.error("钉钉推送消息出现错误 {}", e.toString());
        }
    }

    private void sendDingTalkMsg(String token, MsgRecordVO msgRecordVO, Long agentId) throws ApiException {
        List<MsgBody> contents = msgRecordVO.getContents();
        List<Receiver> receivers = msgRecordVO.getReceivers();
        if (contents == null) {
            MsgMiddleResult msgMiddleResult = generateMsgMiddleResult(receivers, PushResultEnum.PUSH_MSG_INVALID);
            msgRecordVO.getResults().add(msgMiddleResult);
            return;
        }
        // 获取用户id，1.先判断是否包含all2.如果不包含，则通过手机号获取用户id
        String pushUserId;
        Map<String, Receiver> phoneReceiverMap = receivers.stream().collect(Collectors.toMap(Receiver::getReceiverMobilePhone, Function.identity(), (t1, t2) -> t1));
        Map<String, Receiver> dingTalkUserIdReceiverMap = new HashMap<>();
        if (phoneReceiverMap.keySet().contains(CommonConstant.ALL)) {
            pushUserId = CommonConstant.ALL;
            dingTalkUserIdReceiverMap.put(CommonConstant.ALL, phoneReceiverMap.get(CommonConstant.ALL));
        } else {
            List<SysUserInfoDTO> sysUserInfoDTOList = getPushUserId(msgRecordVO, token);
            if (CollectionUtils.isEmpty(sysUserInfoDTOList)) {
                return;
            }
            dingTalkUserIdReceiverMap = sysUserInfoDTOList.stream().collect(Collectors.toMap(SysUserInfoDTO::getUserId,
                    obj -> phoneReceiverMap.get(obj.getMobilePhone()), (t1, t2) -> t1));
            pushUserId = StringUtils.join(dingTalkUserIdReceiverMap.keySet(), ",");
        }
        if (StringUtils.isEmpty(pushUserId)) {
            if (msgRecordVO.getResults().size() < 1) {
                List<Receiver> nullUser = new ArrayList<>();
                nullUser.add(new Receiver().setReceiverType(RangeTypeEnum.PHONE.getCode()));
                MsgMiddleResult msgMiddleResult = generateMsgMiddleResult(nullUser, PushResultEnum.NO_RECEIVER);
                msgRecordVO.getResults().add(msgMiddleResult);
            }
            return;
        }
        DingTalkClient client = new DefaultDingTalkClient(asyncsendV2Url);
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        if (CommonConstant.ALL.equals(pushUserId)) {
            request.setToAllUser(true);
        } else {
            request.setToAllUser(false);
            request.setUseridList(pushUserId);
        }
        request.setAgentId(agentId);
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
        msg.setMsgtype(CommonConstant.TEXT);
        msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
        msg.getText().setContent(contents.get(0).getContent());
        request.setMsg(msg);
        OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request, token);
        DingTalkResponse dingTalkResponse = JSONObject.parseObject(response.getBody(), DingTalkResponse.class);
        log.info(" 钉钉推送返回结果 {} ", dingTalkResponse.toString());
        if (!"0".equals(dingTalkResponse.getErrCode())) {
            log.error("{} 钉钉消息在推送中发生意料之外的 {}", msgRecordVO, dingTalkResponse);
            MsgMiddleResult msgMiddleResult = generateMsgMiddleResult(receivers, PushResultEnum.PUSH_DINGTALK_FAIL);
            msgRecordVO.getResults().add(msgMiddleResult);
        } else {
            client = new DefaultDingTalkClient(sendresultUrl);
            OapiMessageCorpconversationGetsendresultRequest request1 = new OapiMessageCorpconversationGetsendresultRequest();
            request1.setAgentId(agentId);
            request1.setTaskId(response.getTaskId());
            OapiMessageCorpconversationGetsendresultResponse response1 = client.execute(request1, token);
            if (!"0".equals(response1.getErrorCode())) {
                log.error("{} 钉钉消息在推送中发生意料之外的 {}", msgRecordVO, response1.getErrmsg());
                MsgMiddleResult msgMiddleResult = generateMsgMiddleResult(receivers, PushResultEnum.PUSH_DINGTALK_FAIL);
                msgRecordVO.getResults().add(msgMiddleResult);
                return;
            }
            Map map = JSONObject.parseObject(response1.getBody(), Map.class);
            log.info(" 查看钉钉推送进度返回结果 {}", map.toString());
            Map map1 = (Map) map.get("send_result");
            //无效用户
            List<String> invalidUserIdList = (List) map1.get("invalid_user_id_list");
            //流控用户
            List<String> forbiddenUserIdList = (List) map1.get("forbidden_user_id_list");
            //发送失败用户
            List<String> failedUserIdList = (List) map1.get("failed_user_id_list");
            if (CollectionUtils.isNotEmpty(invalidUserIdList)) {
                log.error("{} 钉钉消息在推送中发生意料之外的异常 {}", msgRecordVO, map);
                receivers = processAbnormalReceivers(invalidUserIdList, dingTalkUserIdReceiverMap);
                MsgMiddleResult msgMiddleResult = generateMsgMiddleResult(receivers, PushResultEnum.PUSH_DINGTALK_FAIL);
                msgRecordVO.getResults().add(msgMiddleResult);
            } else if (CollectionUtils.isNotEmpty(forbiddenUserIdList)) {
                log.error("{} 钉钉消息在推送中发生意料之外的异常 {}", msgRecordVO, map);
                receivers = processAbnormalReceivers(forbiddenUserIdList, dingTalkUserIdReceiverMap);
                MsgMiddleResult msgMiddleResult = generateMsgMiddleResult(receivers, PushResultEnum.PUSH_DINGTALK_FORBIDDEN);
                msgRecordVO.getResults().add(msgMiddleResult);
            } else if (CollectionUtils.isNotEmpty(failedUserIdList)) {
                log.error("{} 钉钉消息在推送中发生意料之外的异常 {}", msgRecordVO, map);
                receivers = processAbnormalReceivers(forbiddenUserIdList, dingTalkUserIdReceiverMap);
                MsgMiddleResult msgMiddleResult = generateMsgMiddleResult(receivers, PushResultEnum.PUSH_DINGTALK_FAIL);
                msgRecordVO.getResults().add(msgMiddleResult);
            } else {
                receivers = receivers.stream().filter(
                        receiver -> {
                            String receiverMobilePhone = receiver.getReceiverMobilePhone();
                            if (CollectionUtils.isNotEmpty(invalidUserIdList) && invalidUserIdList.contains(receiverMobilePhone)) {
                                return false;
                            }
                            if (CollectionUtils.isNotEmpty(forbiddenUserIdList) && forbiddenUserIdList.contains(receiverMobilePhone)) {
                                return false;
                            }
                            if (CollectionUtils.isNotEmpty(failedUserIdList) && failedUserIdList.contains(receiverMobilePhone)) {
                                return false;
                            }
                            return true;
                        }
                ).collect(Collectors.toList());
                MsgMiddleResult msgMiddleResult = generateMsgMiddleResult(receivers, PushResultEnum.PUSH_SUCCESS);
                msgRecordVO.getResults().add(msgMiddleResult);
            }
        }
    }

    /**
     * 处理不正常的接收者
     *
     * @param abnormalUserIdList
     * @return
     */
    private List<Receiver> processAbnormalReceivers(List<String> abnormalUserIdList, Map<String, Receiver> dingTalkUserIdReceiverMap) {
        List<Receiver> receivers = abnormalUserIdList.stream().map(
                forbiddenUserId -> dingTalkUserIdReceiverMap.get(forbiddenUserId)).collect(Collectors.toList());
        return receivers;
    }

    private List<SysUserInfoDTO> getPushUserId(MsgRecordVO msgRecordVO, String token) {
        String tenantCode = msgRecordVO.getTenantCode();
        List<String> mobilePhones = msgRecordVO.getReceivers().stream().map(Receiver::getReceiverMobilePhone).collect(Collectors.toList());
        List<SysUserInfoDTO> normalSysUserInfoList = new ArrayList<>();
        List<SysUserInfoDTO> sysUserInfoList = null/*sysUserInfoService.getUserIdByMobile(mobilePhones)*/;
        List<String> ids = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(sysUserInfoList)) {
            // 查询出的所有手机号码
            List<String> mobilePhoneList = sysUserInfoList.stream().map(
                    sysUserInfoDTO -> {
                        ids.add(sysUserInfoDTO.getUserId());
                        return sysUserInfoDTO.getMobilePhone();
                    }
            ).collect(Collectors.toList());
            normalSysUserInfoList.addAll(sysUserInfoList);
            // 求差集-没有对应用户信息的手机号
            mobilePhones.removeAll(mobilePhoneList);
        }
        // 求差集后如果userIds不为空，则调用api查询，查询后存入数据库
        if (CollectionUtils.isNotEmpty(mobilePhones)) {
            List<Receiver> receivers = new ArrayList<>();
            List<String> mobilePhoneList = new ArrayList<>();
            List<SysUserInfoDTO> noSyncUserInfoList = new ArrayList<>();
            for (String mobilePhone : mobilePhones) {
                String id = getUserIdByMobile(mobilePhone, token);
                if (StringUtils.isNotEmpty(id)) {
                    ids.add(id);
                    SysUserInfoDTO sysUserInfoDTO = new SysUserInfoDTO();
                    sysUserInfoDTO.setUserId(id);
                    sysUserInfoDTO.setMobilePhone(mobilePhone);
                    sysUserInfoDTO.setTenantCode(tenantCode);
                    sysUserInfoDTO.setCreator("admin");
                    sysUserInfoDTO.setModifier("admin");
                    noSyncUserInfoList.add(sysUserInfoDTO);
                } else {
                    receivers.add(new Receiver().setReceiverType(RangeTypeEnum.PHONE.getCode())
                            .setReceiverMobilePhone(mobilePhone));
                    mobilePhoneList.add(mobilePhone);
                }
                if (CollectionUtils.isNotEmpty(receivers)) {
                    MsgMiddleResult msgMiddleResult = new MsgMiddleResult()
                            .setReceivers(receivers)
                            .setPushResultCode(PushResultEnum.PUSH_DINGTALK_USER_NOTEXIT.getErrorCode())
                            .setPushResultDescription(PushResultEnum.PUSH_DINGTALK_USER_NOTEXIT.getDescription() + ":" + mobilePhone);
                    msgRecordVO.getResults().add(msgMiddleResult);
                    List<Receiver> receivers1 = msgRecordVO.getReceivers();
                    receivers1 = receivers1.stream().filter(
                            receiver -> {
                                if (mobilePhoneList.contains(receiver.getReceiverMobilePhone())) {
                                    return false;
                                }
                                return true;
                            }
                    ).collect(Collectors.toList());
                    msgRecordVO.setReceivers(receivers1);
                }
            }
            if (CollectionUtils.isNotEmpty(noSyncUserInfoList)) {
                // sysUserInfoService.batchInsert(noSyncUserInfoList);
                normalSysUserInfoList.addAll(noSyncUserInfoList);
            }
        }
        return normalSysUserInfoList;
    }


    public String getUserIdByMobile(String mobilePhone, String token) {
        DingTalkClient client = new DefaultDingTalkClient(userIdByPhoneUrl);
        OapiUserGetByMobileRequest request = new OapiUserGetByMobileRequest();
        request.setMobile(mobilePhone);
        OapiUserGetByMobileResponse execute = null;
        try {
            execute = client.execute(request, token);
        } catch (Exception e) {
            log.error(" 获取钉钉用户钉钉id时出现错误 {} ", e.toString());
        }
        if (null == execute) {
            return null;
        }
        return execute.getUserid();
    }

    private MsgMiddleResult generateMsgMiddleResult(List<Receiver> reveivers, PushResultEnum pushResult) {
        return new MsgMiddleResult()
                .setReceivers(reveivers)
                .setPushResultCode(pushResult.getErrorCode())
                .setPushResultDescription(pushResult.getDescription());
    }
}
